package com.brownmunoz.companyjcr.data.jcr;
/**
 *    Copyright 2011 Eric Brown-Munoz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

import java.io.OutputStream;

import javax.jcr.Credentials;
import javax.jcr.LoginException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.commons.xml.ToXmlContentHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import com.brownmunoz.companyjcr.data.DataException;

public class JackRabbitHelper {

	// Injected
	private Repository repository;
	
	protected static final String NEXT_ID = "nextID";
		
	private Logger logger = LoggerFactory.getLogger(JackRabbitHelper.class);
	/*
	 * Intended for use by Tests (outside of Spring AC).
	 */
	protected JackRabbitHelper(Repository repository) {
		this.repository = repository;
	}
	
	public JackRabbitHelper() {
	}

	public Repository getRepository() {
		return repository;
	}
	
	/**
	 * Opens and returns a basic anonymous session. Note: the caller should ensure
	 * that session.logout() is called on the returned session.
	 * 
	 * @return an open JCR session for the "default" workspace
	 * @throws LoginException
	 * @throws NoSuchWorkspaceException
	 * @throws RepositoryException
	 */
	public Session openSession() throws LoginException, NoSuchWorkspaceException, RepositoryException {
		Credentials creds = new SimpleCredentials("eric", "".toCharArray());
		Session session = repository.login(creds, "default");
		return session;
	}
	
	// Wired
	public void setRepository(Repository repository) {
		this.repository = repository;
	}
	
	/* (non-Javadoc)
	 * @see com.brownmunoz.companyjcr.data.CompanyDAO#generateXML(java.io.OutputStream)
	 */
	public void generateRepositoryXML(OutputStream os, String node) throws DataException {
		Session session = null;
		try {
			session = openSession();
			ContentHandler contentHandler = new ToXmlContentHandler(os);
			session.exportDocumentView("/", contentHandler, true, false);
			
		} catch (RepositoryException re) {
			throw new DataException("Error creating company node.", re);
		} catch (SAXException e) {
			throw new DataException (e);
		} finally {
			session.logout();
		}
	}
	
	/**
	 * This depends on the fact that there is only one CompanyDAO keeping track of IDs. If there is more than
	 * one, then some locking scheme will be required.
	 * 
	 * @return
	 * @throws DataException 
	 */
	public synchronized long getUniqueID (String parentNodeName) throws DataException  {
		Session session = null;
		long nextUniqueID;
		
		try {
			session = openSession();
			Node root = session.getRootNode();
			Node parentNode;
			
			if (root.hasNode(parentNodeName)) {
				parentNode = root.getNode(parentNodeName);
			} else {
				parentNode = root.addNode(parentNodeName);
			}
			
			if (parentNode.hasProperty(NEXT_ID)) {
				nextUniqueID = parentNode.getProperty(NEXT_ID).getLong();
			} else {
				nextUniqueID = 0;
			}
			
			parentNode.setProperty( NEXT_ID, nextUniqueID + 1);
			session.save();
		} catch (RepositoryException e) {
			logger.error("RepositoryException Getting Unique ID", e);
			throw new DataException("Unable to get Unique ID for node " + parentNodeName, e);
		} finally {
			if (session != null) {
				session.logout();
			}
		}

		return nextUniqueID;
	}

	/**
	 * Shuts down the repository (only does work if repository is a Jackrabbit
	 * repository.
	 */
	public void shutdownRepository() {
		if ((this.repository != null) && 
				(this.repository instanceof JackrabbitRepository)) {
			((JackrabbitRepository)this.repository).shutdown();
		}
	}
	
}
